package com.itshare.video.common.aop;

import com.itshare.video.common.aop.bean.AopParameterAnnotationHolder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @Author lyr
 * @create 2020/10/24 18:16
 */
public class AopUtils {

    /**
     * 获取 jointPoint 注解
     * @return
     */
    public  static <T extends Annotation> T getAnnotation(JoinPoint pjp, Class<T> clazz) {
        return ((MethodSignature)pjp.getSignature()).getMethod().getAnnotation(clazz);
    }

    /**
     * 获取被拦截的方法
     * @param pjp
     * @return
     */
    public static Method getAopMethod(JoinPoint pjp) {
        return ((MethodSignature)pjp.getSignature()).getMethod();
    }

    /**
     * 是否存在某个注解
     * @param pjp
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T extends Annotation> boolean isAnnotationPresent(JoinPoint pjp,Class<T> clazz) {
        return getAopMethod(pjp).isAnnotationPresent(clazz);
    }

    /**
     * 方法调用后返回的函数值类型
     * @param pjp
     * @return
     */
    public static AnnotatedType getMethodReturnType(ProceedingJoinPoint pjp) {
       return getAopMethod(pjp).getAnnotatedReturnType();
    }

    /**
     * 获取方法的注解
     * @param pjp
     * @return
     */
    public  static Annotation[] getAnnotations(JoinPoint pjp) {
        return ((MethodSignature)pjp.getSignature()).getMethod().getAnnotations();
    }


    /**
     * public 方法，返回 public
     * @param pjp
     * @return
     */
    public  static String getModifierByJointPoint(JoinPoint pjp) {
        return Modifier.toString(getAopMethod(pjp).getModifiers());
    }


    /**
     * 获取 Aop 切入的 运行方法的 参数列表
     * @param point
     * @return
     */
    public static AnnotatedType[] getAnnotatedParameterTypes(JoinPoint point) {
        return getAopMethod(point)
                .getAnnotatedParameterTypes();
    }


    /**
     * 参数注解
     * (@RequestParam int i)
     *  parameters{ i,RequestParam }
     *
     * @param point
     * @return
     */
    public static List<AopParameterAnnotationHolder> getParameterAnnotations(JoinPoint point) {
        Method method  = getAopMethod(point);

        Parameter[] parameters = method.getParameters();
        return Arrays.stream(parameters)
                .map(parameter -> {
                    AopParameterAnnotationHolder holder = new AopParameterAnnotationHolder() ;
                    return holder.setParameter(parameter)
                            .setAnnotations(Arrays.asList(parameter.getAnnotations()));
                })
                .collect(Collectors.toList());
    }


    /**
     * 获取方法参数的个数
     * @param point
     * @return
     */
    public static int getMethodParameterCount(JoinPoint point) {
        return getAopMethod(point).getParameterCount();
    }


    public static <T> void parsingObjectField(T object, Consumer<Field> consumer) {
        Class clazz = object.getClass();
        for (Field field: clazz.getDeclaredFields()) {
            consumer.accept(field);
        }
    }

    static Field[] getFields(Object object) {
        return object.getClass().getDeclaredFields();
    }


    /**
     * pojo 的某个字段是否包含某个注解
     * @param object pojo
     * @param annotationClazz
     * @param <T>
     * @return
     */
    public static  <T extends Annotation> boolean fieldContainsAnnotation(Object object, Class<T> annotationClazz) {
        for (Field field: getFields(object)) {
            if(field.isAnnotationPresent(annotationClazz)) {
                return true;
            }
        }
        return false;
    }












}
